{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Name: Md Mintu Miah, ID: 1001405116"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# IMDB-sentiment Analysis Using Naive Bayes Classifier"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Test classification is done for the purpose of finding tags or catagories of the text according to their contents. In this analysis, the data set is a collection of 50,000 reviews from IMDB. I have taken the process data from https://www.kaggle.com/lakshmi25npathi/sentiment-analysis-of-imdb-movie-reviews/data and orginal data is available in here http://ai.stanford.edu/~amaas/data/sentiment/. The purpose of this analysis was exploring the naive bayes classification with text data. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Import the data and explore the contents"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# Read The data\n",
"import pandas as pd\n",
"import numpy as np\n",
"from sklearn.naive_bayes import MultinomialNB"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [],
"source": [
"# Import the data and see the data type"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
review
\n",
"
sentiment
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
One of the other reviewers has mentioned that ...
\n",
"
positive
\n",
"
\n",
"
\n",
"
1
\n",
"
A wonderful little production. <br /><br />The...
\n",
"
positive
\n",
"
\n",
"
\n",
"
2
\n",
"
I thought this was a wonderful way to spend ti...
\n",
"
positive
\n",
"
\n",
"
\n",
"
3
\n",
"
Basically there's a family where a little boy ...
\n",
"
negative
\n",
"
\n",
"
\n",
"
4
\n",
"
Petter Mattei's \"Love in the Time of Money\" is...
\n",
"
positive
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" review sentiment\n",
"0 One of the other reviewers has mentioned that ... positive\n",
"1 A wonderful little production.
The... positive\n",
"2 I thought this was a wonderful way to spend ti... positive\n",
"3 Basically there's a family where a little boy ... negative\n",
"4 Petter Mattei's \"Love in the Time of Money\" is... positive"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data=pd.read_csv('C:/Users/mxm5116/Desktop/Data Mining/IMDB Dataset.csv')\n",
"data.head()"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(50000, 2)\n"
]
}
],
"source": [
"# Check the shape of the data\n",
"print(data.shape)"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
review
\n",
"
sentiment
\n",
"
\n",
" \n",
" \n",
"
\n",
"
count
\n",
"
50000
\n",
"
50000
\n",
"
\n",
"
\n",
"
unique
\n",
"
49582
\n",
"
2
\n",
"
\n",
"
\n",
"
top
\n",
"
Loved today's show!!! It was a variety and not...
\n",
"
positive
\n",
"
\n",
"
\n",
"
freq
\n",
"
5
\n",
"
25000
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" review sentiment\n",
"count 50000 50000\n",
"unique 49582 2\n",
"top Loved today's show!!! It was a variety and not... positive\n",
"freq 5 25000"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Now lets, see the summary of the data set\n",
"data.describe()"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"positive 25000\n",
"negative 25000\n",
"Name: sentiment, dtype: int64"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Check the positive and negative number of sentiment\n",
"data['sentiment'].value_counts()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# a. Divide the dataset as train,and test¶ data sets"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# First clear and normalized the data and divide again as normalized train, and test data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Now clean the text"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# Import library\n",
"from bs4 import BeautifulSoup\n",
"import re,string,unicodedata\n",
"# Removing the html strips\n",
"def strip_html(text):\n",
" soup = BeautifulSoup(text, \"html.parser\")\n",
" return soup.get_text()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# Remove the square brackets\n",
"def remove_between_square_brackets(text):\n",
" return re.sub('\\[[^]]*\\]', '', text)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# Remoove the noisy text\n",
"def denoise_text(text):\n",
" text = strip_html(text)\n",
" text = remove_between_square_brackets(text)\n",
" return text\n",
"#Apply function on review column\n",
"data['review']=data['review'].apply(denoise_text)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Now remove special character and apply function for the review colums\n",
"def remove_special_characters(text, remove_digits=True):\n",
" pattern=r'[^a-zA-z0-9\\s]'\n",
" text=re.sub(pattern,'',text)\n",
" return text\n",
"data['review']=data['review'].apply(remove_special_characters)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# Streaming the text\n",
"from sklearn.feature_extraction.text import CountVectorizer\n",
"from sklearn.feature_extraction.text import TfidfVectorizer\n",
"import nltk\n",
"def simple_stemmer(text):\n",
" ps=nltk.porter.PorterStemmer()\n",
" text= ' '.join([ps.stem(word) for word in text.split()])\n",
" return text\n",
"#Apply function on review column\n",
"data['review']=data['review'].apply(simple_stemmer)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
review
\n",
"
sentiment
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
one of the other review ha mention that after ...
\n",
"
positive
\n",
"
\n",
"
\n",
"
1
\n",
"
A wonder littl product the film techniqu is ve...
\n",
"
positive
\n",
"
\n",
"
\n",
"
2
\n",
"
I thought thi wa a wonder way to spend time on...
\n",
"
positive
\n",
"
\n",
"
\n",
"
3
\n",
"
basic there a famili where a littl boy jake th...
\n",
"
negative
\n",
"
\n",
"
\n",
"
4
\n",
"
petter mattei love in the time of money is a v...
\n",
"
positive
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" review sentiment\n",
"0 one of the other review ha mention that after ... positive\n",
"1 A wonder littl product the film techniqu is ve... positive\n",
"2 I thought thi wa a wonder way to spend time on... positive\n",
"3 basic there a famili where a littl boy jake th... negative\n",
"4 petter mattei love in the time of money is a v... positive"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data.head()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
"
],
"text/plain": [
" review sentiment score\n",
"0 one of the other review ha mention that after ... positive 1\n",
"1 A wonder littl product the film techniqu is ve... positive 1\n",
"2 I thought thi wa a wonder way to spend time on... positive 1\n",
"3 basic there a famili where a littl boy jake th... negative 0\n",
"4 petter mattei love in the time of money is a v... positive 1"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Now take the positive sentiment data from training set\n",
"train_data=data[:4000]\n",
"positive_docs=train_data.loc[train_data['sentiment']!=0]\n",
"positive_docs.head()"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['A wonder littl product the film techniqu is veri unassum veri oldtimebbc fashion and give a comfort and sometim discomfort sens of realism to the entir piec the actor are extrem well chosen michael sheen not onli ha got all the polari but he ha all the voic down pat too you can truli see the seamless edit guid by the refer to william diari entri not onli is it well worth the watch but it is a terrificli written and perform piec A master product about one of the great master of comedi and hi life the realism realli come home with the littl thing the fantasi of the guard which rather than use the tradit dream techniqu remain solid then disappear It play on our knowledg and our sens particularli with the scene concern orton and halliwel and the set particularli of their flat with halliwel mural decor everi surfac are terribl well done',\n",
" 'I thought thi wa a wonder way to spend time on a too hot summer weekend sit in the air condit theater and watch a lightheart comedi the plot is simplist but the dialogu is witti and the charact are likabl even the well bread suspect serial killer while some may be disappoint when they realiz thi is not match point 2 risk addict I thought it wa proof that woodi allen is still fulli in control of the style mani of us have grown to lovethi wa the most Id laugh at one of woodi comedi in year dare I say a decad while ive never been impress with scarlet johanson in thi she manag to tone down her sexi imag and jump right into a averag but spirit young womanthi may not be the crown jewel of hi career but it wa wittier than devil wear prada and more interest than superman a great comedi to go see with friend',\n",
" 'basic there a famili where a littl boy jake think there a zombi in hi closet hi parent are fight all the timethi movi is slower than a soap opera and suddenli jake decid to becom rambo and kill the zombieok first of all when your go to make a film you must decid if it a thriller or a drama As a drama the movi is watchabl parent are divorc argu like in real life and then we have jake with hi closet which total ruin all the film I expect to see a boogeyman similar movi and instead i watch a drama with some meaningless thriller spots3 out of 10 just for the well play parent descent dialog As for the shot with jake just ignor them',\n",
" 'petter mattei love in the time of money is a visual stun film to watch Mr mattei offer us a vivid portrait about human relat thi is a movi that seem to be tell us what money power and success do to peopl in the differ situat we encount thi be a variat on the arthur schnitzler play about the same theme the director transfer the action to the present time new york where all these differ charact meet and connect each one is connect in one way or anoth to the next person but no one seem to know the previou point of contact stylishli the film ha a sophist luxuri look We are taken to see how these peopl live and the world they live in their own habitatth onli thing one get out of all these soul in the pictur is the differ stage of loneli each one inhabit A big citi is not exactli the best place in which human relat find sincer fulfil as one discern is the case with most of the peopl we encounterth act is good under Mr mattei direct steve buscemi rosario dawson carol kane michael imperioli adrian grenier and the rest of the talent cast make these charact come alivew wish Mr mattei good luck and await anxious for hi next work']"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# make the list of positive sentiment\n",
"train_pos_reviews=positive_docs['review']\n",
"train_pos_voca=train_pos_reviews.values.tolist()\n",
"train_pos_voca[1:5]"
]
},
{
"cell_type": "code",
"execution_count": 74,
"metadata": {},
"outputs": [],
"source": [
"# Join the positive sentiment with single dot\n",
"train_pos_voca='.'.join(train_pos_voca)"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3978\n"
]
}
],
"source": [
"# Now calculate the number of positive documents having the\n",
"words=[\"the\"]\n",
"sentences = train_pos_voca\n",
"count=0\n",
"for sentence in sentences :\n",
" for word in words :\n",
" if word in sentence :\n",
" count=count+1\n",
" #print(count)\n",
" #print(count)\n",
"num_of_pos_documents_containing_the=count\n",
"print(num_of_pos_documents_containing_the)"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"4000\n"
]
}
],
"source": [
"# Find the totl positive documents in training data set\n",
"num_of_all_pos_documents=positive_docs['review'].count()\n",
"print(num_of_all_pos_documents)"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0.9945\n"
]
}
],
"source": [
"# Now calculate P[“the” | Positive] = # of positive documents containing “the” / num of all positive review documents\n",
"probability_0f_the_in_positive_docs=num_of_pos_documents_containing_the/num_of_all_pos_documents\n",
"print(probability_0f_the_in_positive_docs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# d.\tCalculate accuracy using dev dataset \n",
"\t# Conduct five fold cross validation\n"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"10"
]
},
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Convert the data in vector fpormate\n",
"tf_idf_vect = TfidfVectorizer(ngram_range=(1,2))\n",
"tf_idf_train = tf_idf_vect.fit_transform(X_train)\n",
"tf_idf_test = tf_idf_vect.transform(X_test)\n",
"\n",
"alpha_range = list(np.arange(0,10,1))\n",
"len(alpha_range)"
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"C:\\Users\\mxm5116\\Anaconda3\\lib\\site-packages\\sklearn\\naive_bayes.py:507: UserWarning: alpha too small will result in numeric errors, setting alpha = 1.0e-10\n",
" 'setting alpha = %.1e' % _ALPHA_MIN)\n",
"C:\\Users\\mxm5116\\Anaconda3\\lib\\site-packages\\sklearn\\naive_bayes.py:507: UserWarning: alpha too small will result in numeric errors, setting alpha = 1.0e-10\n",
" 'setting alpha = %.1e' % _ALPHA_MIN)\n",
"C:\\Users\\mxm5116\\Anaconda3\\lib\\site-packages\\sklearn\\naive_bayes.py:507: UserWarning: alpha too small will result in numeric errors, setting alpha = 1.0e-10\n",
" 'setting alpha = %.1e' % _ALPHA_MIN)\n",
"C:\\Users\\mxm5116\\Anaconda3\\lib\\site-packages\\sklearn\\naive_bayes.py:507: UserWarning: alpha too small will result in numeric errors, setting alpha = 1.0e-10\n",
" 'setting alpha = %.1e' % _ALPHA_MIN)\n",
"C:\\Users\\mxm5116\\Anaconda3\\lib\\site-packages\\sklearn\\naive_bayes.py:507: UserWarning: alpha too small will result in numeric errors, setting alpha = 1.0e-10\n",
" 'setting alpha = %.1e' % _ALPHA_MIN)\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 0.8233\n",
"1 0.8845749999999999\n",
"2 0.879425\n",
"3 0.8753749999999998\n",
"4 0.8727500000000001\n",
"5 0.8703\n",
"6 0.8679499999999999\n",
"7 0.86595\n",
"8 0.8638\n",
"9 0.86205\n"
]
}
],
"source": [
"# take different values of alpha in cross validation and finding the accuracy score\n",
"from sklearn.naive_bayes import MultinomialNB\n",
"\n",
"alpha_scores=[]\n",
"\n",
"for a in alpha_range:\n",
" clf = MultinomialNB(alpha=a)\n",
" scores = cross_val_score(clf, tf_idf_train, y_train, cv=5, scoring='accuracy')\n",
" alpha_scores.append(scores.mean())\n",
" print(a,scores.mean())"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"
"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# Plot b/w misclassification error and CV mean score.\n",
"import matplotlib.pyplot as plt\n",
"\n",
"MSE = [1 - x for x in alpha_scores]\n",
"\n",
"\n",
"optimal_alpha_bnb = alpha_range[MSE.index(min(MSE))]\n",
"\n",
"# plot misclassification error vs alpha\n",
"plt.plot(alpha_range, MSE)\n",
"\n",
"plt.xlabel('hyperparameter alpha')\n",
"plt.ylabel('Misclassification Error')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 68,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"optimal_alpha_bnb\n",
"\n",
"# For alpha =1, we have got minimum misscalculation error"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# e.\tDo following experiments\n",
"\tCompare the effect of Smoothing\n",
"\tDerive Top 10 words that predicts positive and negative class \n",
" •\tP[Positive| word] \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Effects of non-smoothing and smoothing "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# We have already got the effects of smoothing and non-smoothing. When we have considered alpha=0 (non-smoothing), we got the accuracy 82.33% whereas with smoothing our accuacy is always greater than non-smoothing conditions. We have got best smoothing parapmeter alpha=1 with hoighest accuracy 88.46%"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"[nltk_data] Downloading package stopwords to\n",
"[nltk_data] C:\\Users\\mxm5116\\AppData\\Roaming\\nltk_data...\n",
"[nltk_data] Package stopwords is already up-to-date!\n"
]
},
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Now lets see the highest positive and negative words that has highest sentiment prediction capacity\n",
"import re\n",
"import string\n",
"import nltk\n",
"from nltk.corpus import stopwords\n",
"from nltk.stem import PorterStemmer\n",
"from nltk.stem.wordnet import WordNetLemmatizer\n",
"nltk.download('stopwords')"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [],
"source": [
"# Now we will remove stop words as it does not carry significant meaning and will store positive and negative word for selections\n",
"stop = set(stopwords.words('english')) \n",
"sno = nltk.stem.SnowballStemmer('english') \n",
"def cleanhtml(sentence): \n",
" cleanr = re.compile('<.*?>')\n",
" cleantext = re.sub(cleanr, ' ', sentence)\n",
" return cleantext\n",
"def cleanpunc(sentence): \n",
" cleaned = re.sub(r'[?|!|\\'|\"|#]',r'',sentence)\n",
" cleaned = re.sub(r'[.|,|)|(|\\|/]',r' ',cleaned)\n",
" return cleaned\n",
"i=0\n",
"str1=' '\n",
"final_string=[]\n",
"all_positive_words=[] \n",
"all_negative_words=[] \n",
"s=''\n",
"for sent in data['review'].values:\n",
" filtered_sentence=[]\n",
" sent=cleanhtml(sent) \n",
" for w in sent.split():\n",
" for cleaned_words in cleanpunc(w).split():\n",
" if((cleaned_words.isalpha()) & (len(cleaned_words)>2)): \n",
" if(cleaned_words.lower() not in stop):\n",
" s=(sno.stem(cleaned_words.lower())).encode('utf8')\n",
" filtered_sentence.append(s)\n",
" if (data['score'].values)[i] == 1: \n",
" all_positive_words.append(s) \n",
" if(data['score'].values)[i] == 0:\n",
" all_negative_words.append(s) \n",
" else:\n",
" continue\n",
" else:\n",
" continue \n",
" \n",
" str1 = b\" \".join(filtered_sentence) \n",
" \n",
" final_string.append(str1)\n",
" i+=1"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3062885\n",
"3002812\n"
]
}
],
"source": [
"total_positive_words = len(all_positive_words)\n",
"total_negative_words = len(all_negative_words)\n",
"print(total_positive_words)\n",
"print(total_negative_words)"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [],
"source": [
"import random\n",
"apw = random.sample(all_positive_words, 10000)\n",
"anw = random.sample(all_negative_words, 10000)\n",
"freq_negative_words = {x:anw.count(x) for x in anw}\n",
"freq_positive_words = {x:apw.count(x) for x in apw}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#Lets see positive sentiment first"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"